package edu.utexas.mapreduce;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;
import java.util.TreeMap;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

public class JarClassLoader extends ClassLoader {

	Map<String, byte[]> classMap = new TreeMap<String, byte[]>();
	
	JarClassLoader(JarInputStream jarInput) throws IOException {
		super(); // default ClassLoader constructor links to SystemClassLoader 
		
		//
		// For each entry in the Jar file, get the name and read the binary
		// data.  The size of the data is unknown, so read one byte at a 
		// time.
		//
		JarEntry entry;
		ArrayList<Byte> classData = new ArrayList<Byte>();
		byte[] b = new byte[1];
		while ((entry = jarInput.getNextJarEntry()) != null) {
			classData.clear();
			String className = entry.getName();
			while (jarInput.read(b, 0, 1) != -1) {
				classData.add(b[0]);
			}
			// convert from Byte[] to byte[]
			byte[] classByteArray = new byte[classData.size()];
			for(int i = 0; i < classData.size(); i++) {
				classByteArray[i] = classData.get(i).byteValue();
			}
			// link the class name to the class binary data
			classMap.put(className, classByteArray);
            
            // System.out.println("-- read class " + className + " size " + classData.size());
		}
	}
	
	
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		System.out.println("-- find class : " + name);
		String jarClassName = name.replace('.', '/') + ".class";
		if (!classMap.containsKey(jarClassName)) {
			throw new ClassNotFoundException();
		}
		System.out.println("-- define class : " + name);
		byte[] classData = classMap.get(jarClassName);
		return defineClass(name, classData, 0, classData.length);
	}
}
